package com.soilflow.know.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.soilflow.common.core.domain.entity.*;
import com.soilflow.common.enums.BetChargeFee;
import com.soilflow.common.enums.BetRate;
import com.soilflow.common.utils.bean.BeanUtils;
import com.soilflow.know.mapper.GamesBidHistoryMapper;
import com.soilflow.know.mapper.GamesInfoMapper;
import com.soilflow.know.mapper.GamesUserScoreMapper;
import com.soilflow.know.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

@Service
public class GamesBidHistoryServiceImpl extends ServiceImpl<GamesBidHistoryMapper, GamesBidHistory> implements GamesBidHistoryService {

    @Autowired
    private GamesBetHistoryService gamesBetHistoryService;

    @Autowired
    private GamesUserScoreService gamesUserScoreService;
    @Autowired
    private GamesScoreHistoryService gamesScoreHistoryService;

    @Override
    public void scheduler() {
        String channelId = "https://apigx.cn/token/ccd5363c593c11ef82edfdbfd7b55d24/code/jnd28/rows/10/type/fastest.json";
        GamesBidHistory data = this.spider(channelId);

        GamesBidHistory gamesBidHistory = this.selectGamesBidHistoryByBidNo(data.getBidNo());
        if(gamesBidHistory == null){
            data.setCreateTime(new Date());
            // 开奖
            this.insertGamesBidHisotry(data);
            // 派奖
            this.paiJiang(data);
        }

        System.out.println("定时任务爬取开奖数据。。。。");
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doKaijiang(GamesBidHistory Dto){
        this.paiJiang(Dto);
        GamesBidHistory data = new GamesBidHistory();
        data.setStatus("1");
        data.setBidId(Dto.getBidId());
        this.baseMapper.updateByBidId(data);
    }


    // 派奖
    private void paiJiang(GamesBidHistory gamesBidHistory){
        // 这里有一个赔率的问题
        // 大小单双2.8的赔率，并且没有手续费
        // 第一步：查询所有的用户下注记录,逐步派奖
        List<GamesBetHistory> gamesBetHistories = gamesBetHistoryService.selectGamesBetHistoryListByBidNo(gamesBidHistory.getBidNo());
        System.out.println(gamesBetHistories.size()+"个投注。。。。。。。。。。。。。。。。。。");
        System.out.println(gamesBetHistories.size()+"个投注。。。。。。。。。。。。。。。。。。");
        for(GamesBetHistory item : gamesBetHistories){
            //  A 用户 中奖 100元，增加积分记录，修改用户总积分，设置投注记录为已开奖
            // 第一步：计算中奖金额
            BigDecimal prize = BigDecimal.ZERO;
            BigDecimal[] prizeDetails = calPrizeAmount(item, gamesBidHistory);
            for(BigDecimal prizeItem : prizeDetails){
                /*手续费向上取整*/
                if(prizeItem.doubleValue()>0){
                    // 加分时，向下取整
                    prizeItem = new BigDecimal(Math.floor(prizeItem.doubleValue()));
                }else{
                    // 减分时，向上取整
                    prizeItem = new BigDecimal(Math.ceil(prizeItem.doubleValue()));
                }
                prize = prize.add(prizeItem);
            }
            if(prize.compareTo(BigDecimal.ZERO) != 0) {
                // 第二步：修改用户积分
                this.updateUserScore(item, prize);
                System.out.println(prize + "中奖金额。。。。。。。。。。。。。。。。。");
                // 第三步：增加积分增加/减少记录
                this.insertScoreHistory(item, prize);
            }

            // 第四步：修改投注信息为结算完成
            String bidMoneys[] = new String[prizeDetails.length];
            for(int i=0; i<prizeDetails.length; i++){
                bidMoneys[i] = String.format("%.1f", prizeDetails[i].doubleValue());
            }
            item.setBidMoney(String.join(",", bidMoneys));
            System.out.println(item.getBidMoney());
            System.out.println("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
            this.updateBetHistory(item, gamesBidHistory, prize);
        }
    }


    // 修改用户积分
    private void updateUserScore(GamesBetHistory item, BigDecimal prize){
        // 修改积分总额
        GamesUserScore gamesUserScore = new GamesUserScore();
        gamesUserScore.setUserId(item.getUserId());
        gamesUserScore.setScore(prize);
        gamesUserScoreService.addGamesUserScoreOnly(gamesUserScore);
       // gamesUserScoreService.addGamesUserScore(gamesUserScore);
    }

    // 添加中奖记录
    private void insertScoreHistory(GamesBetHistory item, BigDecimal prize){
        // 增加一条积分记录
        GamesUserScore newScore = gamesUserScoreService.selectGamesUserScoreByUserId(item.getUserId());
        GamesScoreHistory gamesScoreHistory = new GamesScoreHistory();
        gamesScoreHistory.setUserId(item.getUserId());
        gamesScoreHistory.setUserName(newScore.getUserName());
        gamesScoreHistory.setType("4");
        gamesScoreHistory.setScore(prize);
        gamesScoreHistory.setUserScore(newScore.getScore());
        gamesScoreHistory.setScoreTime(new Date());
        if(prize.doubleValue()>0){
            gamesScoreHistory.setOrigin("返奖");
        }else{
            gamesScoreHistory.setOrigin("亏损");
        }
        gamesScoreHistoryService.save(gamesScoreHistory);
    }

    // 修改投注记录
    private void updateBetHistory(GamesBetHistory gamesBetHistory, GamesBidHistory gamesBidHistory, BigDecimal prize){
        System.err.println("-------------------------22222222222222222222222222");
        GamesBetHistory data = new GamesBetHistory();
        data.setBetId(gamesBetHistory.getBetId());
        data.setBidAmount(prize);
        data.setBidMoney(gamesBetHistory.getBidMoney());
        data.setStatus("1");
        data.setBidTime(gamesBidHistory.getBidTime());
        data.setBidNumber(gamesBidHistory.getBidNumber());
        data.setBidType(gamesBidHistory.getBidType());
        gamesBetHistoryService.updateGamesBetHistory(data);
    }

    /**
     * * 回本公司里面玩：
     *          * 玩家下注100大，开奖4 7 9，大，不回， 返奖280
     *          * 玩家下注100大，开奖8 7 9，大，回， 返奖100
     *          * 玩家下注100大，开奖8 7 9，小，不回， 返奖0
     *          * 玩家下注100大，开奖8 7 9，小，回， 返奖0
     *          *
     *          * 玩家下注100大双，开奖4 6 8，大双，不回， 返奖-500，另扣手续费
     *          * 玩家下注100大双，开奖4 8 8，大双，回，   返奖100， 另扣手续费
     *          * 玩家下注100大双，开奖4 1 2，非大双 不回，返奖100， 另扣手续费
     *          * 玩家下注100大双，开奖2 1 2，非大双 回，  返奖100， 另扣手续费
     *          *
     *          * 玩家下注100倍数，开奖2 1 2， 回，    返奖200， 另扣手续费
     *          * 玩家下注100倍数，开奖2 1 5， 不回，  返奖20， 另扣手续费
     *          *
     *          * 大小单双，中了➕1.8没中扣1，中了回本不加不减
     *          * 只要不是大双都要加，大双回本就减手续费，大双不回本就减 本金 * 5
     *          // 100元买倍数，中了返200元，扣手费，不中则，返奖20元并扣除手续费
     * @param bet
     * @param gamesBidHistory
     * @return
     */
    private BigDecimal[] calPrizeAmount(GamesBetHistory bet, GamesBidHistory gamesBidHistory){
        // 计算用户的中奖金额(所有选项中奖之和)
        String[] split = bet.getBetData().split("\\+");
        String[] splitMoney = bet.getBetMoney().split(",");
        BigDecimal[] res = new BigDecimal[split.length];

        for(int i=0; i<split.length; i++){
            ArrayList<String> combine = zhongJiangCombine(gamesBidHistory.getBidType());
            BigDecimal zhongjiangRate = getZhongjiangRate(split[i], combine);
            BigDecimal bigDecimal = queryFee(split[i]);

            // 单项中奖金额
            BigDecimal betMoney = new BigDecimal(splitMoney[i]);
            res[i] = zhongjiangRate.subtract(bigDecimal).multiply(betMoney);
        }
        return res;
    }

    private ArrayList<String> zhongJiangCombine(String type){
        ArrayList<String> jiang = new ArrayList<>();
        String[] split = type.split(",");
        if(split.length==3 && split[2].equals("回")){
            jiang.add(split[0]);
            jiang.add(split[1]);
            jiang.add(split[2]);
            jiang.add(split[0]+split[2]);
            jiang.add(split[1]+split[2]);
            jiang.add(split[0]+split[1]+split[2]);
        }else{
            jiang.add(split[0]);
            jiang.add(split[1]);
            jiang.add(split[0]+split[1]);
        }
        return jiang;
    }

    // 查询中奖赔率
    private BigDecimal getZhongjiangRate(String number, ArrayList<String> jiang){
        // 大小单双的返奖方法
        /**
         * * 玩家下注100倍数，开奖2 1 2， 回，    返奖200， 另扣手续费
         * * 玩家下注100倍数，开奖2 1 5， 不回，  返奖20， 另扣手续费
         */
        if(number.equals("大") || number.equals("小") || number.equals("单") || number.equals("双")){
            // 没中就不返奖，中了还要分情况返奖（回本1倍，不回本2.8倍）
            if(containsZhongjiang(number, jiang)){
                if(containsZhongjiang("回", jiang)) {
                    return new BigDecimal(1);
                }
                return new BigDecimal(2.8);
            }
            return BigDecimal.ZERO;
        }

        // 倍数的返奖方法
        if(number.equals("倍数")){
            if(containsZhongjiang("回", jiang)){
                return new BigDecimal(2);
            }else {
                return new BigDecimal(0.2);
            }
        }

        // 组合的返奖方法
        if(number.equals("大单") || number.equals("大双") || number.equals("小单") || number.equals("小双")){
            if(containsZhongjiang(number, jiang)){
                if(containsZhongjiang("回", jiang)){
                    return new BigDecimal(1); // 中了，又开了回，返回本金，只扣手续费
                }else{
                    return new BigDecimal(-4); //最多输5倍，还要扣手续费
                }
            }
            return new BigDecimal(2);
        }
        return new BigDecimal(0);
    }

    public Boolean containsZhongjiang(String type, ArrayList<String> jiang){
        for(int i=0; i<jiang.size(); i++){
            if(type.equals(jiang.get(i))){
                return true;
            }
        }
        return false;
    }

    public BigDecimal queryRate(String code){
        for(BetRate item : BetRate.values()){
            if(code.equals(item.getCode())){
                return item.getRate();
            }
        }
        return BigDecimal.ZERO;
    }

    public BigDecimal queryFee(String code){
        for(BetChargeFee item : BetChargeFee.values()){
            if(code.equals(item.getCode())){
                return item.getRate();
            }
        }
        return BigDecimal.ZERO;
    }


    /**
     * 以get方式调用对方接口方法
     */
    public static String doGet(String pathUrl){
        BufferedReader br = null;
        String result = "";
        try {
            URL url = new URL(pathUrl);
            //打开和url之间的连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //设定请求的方法为"GET"，默认是GET
            //post与get的不同之处在于post的参数不是放在URL字串里面，而是放在http请求的正文内。
            conn.setRequestMethod("GET");
            //设置30秒连接超时
            conn.setConnectTimeout(30000);
            //设置30秒读取超时
            conn.setReadTimeout(30000);
            // 设置是否向httpUrlConnection输出，因为这个是post请求，参数要放在http正文内，因此需要设为true, 默认情况下是false;
            conn.setDoOutput(true);
            // 设置是否从httpUrlConnection读入，默认情况下是true;
            conn.setDoInput(true);
            // Post请求不能使用缓存(get可以不使用)
            conn.setUseCaches(false);
            //设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");  //维持长链接
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
            //连接，从上述url.openConnection()至此的配置必须要在connect之前完成，
            conn.connect();
            //下面的代码相当于，获取调用第三方http接口后返回的结果
            //获取URLConnection对象对应的输入流
            InputStream is = conn.getInputStream();
            //构造一个字符流缓存
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String str = "";
            while ((str = br.readLine()) != null)result += str;
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (br != null){
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public GamesBidHistory spider(String url){


        String pathUrl = "https://apigx.cn/token/817864a0594311efb7c5ed9c309c3b85/code/jnd28/rows/1.json"; // 替换成实际的API地址
        String re=doGet(pathUrl);
        System.out.println(re);
        System.out.println("99999999999999999999999999999999999");
        JSONObject jsonObject = (JSONObject) JSON.parse(re);
        System.out.println("彩票代码："+jsonObject.getString("code"));
        String dataString = jsonObject.getString("data");
        System.out.println(dataString);

        JSONArray jsonArray = (JSONArray) JSON.parse(dataString);
        JSONObject last= (JSONObject)jsonArray.get(0);
        System.out.println("当前最后一期彩票期号："+last.getString("expect"));
        System.out.println("当前最后一期彩票开奖号码："+last.getString("opencode"));

        GamesBidHistory data = new GamesBidHistory();
        data.setBidChannel(url);
        data.setGameId(1L);
        data.setBidTime(new Date());
        data.setBidNo(last.getString("expect"));

        String[] bidData = new String[3];
        String[] opencodes = last.getString("opencode").split(",");
        Integer[] numbers = new Integer[3];
        numbers[0] = Integer.parseInt(opencodes[0]);
        numbers[1] = Integer.parseInt(opencodes[1]);
        numbers[2] = Integer.parseInt(opencodes[2]);
        Arrays.sort(numbers);
        int sum = numbers[0] + numbers[1] + numbers[2];
        bidData[0] = (sum >= 14) ? "大":"小";
        bidData[1] = sum%2==0 ? "双":"单";
        bidData[2] = idHuiBen(numbers[0], numbers[1], numbers[2])?"回":"";

        data.setBidSum(sum+"");
        data.setBidType(String.join(",", bidData));

        data.setBidSum(sum+"");
        data.setBidType(String.join(",", bidData));
        data.setBidNumber(String.join("+", opencodes));
        data.setBidSum(sum+"");
        data.setBidType(String.join(",", bidData));

        return data;

    }

    public boolean idHuiBen(Integer number1, Integer number2, Integer number3){
        /**
         * 每天晚上7点到7点半维护半小时，其它时间正常运行
         * 7点半到7点 11.5小时 * 60 = 690分钟 / 3.5分钟
         * 回： 对子，顺子，豹子，13，14（3数之和） (0 1 2是顺子 0 8 9也是顺子 0 1 9也是顺子)
         */
        //情况1：顺子就是回 (0 1 2是顺子 0 8 9也是顺子 0 1 9也是顺子)
        if(number1 + 1 == number2 && number2 + 1 == number3){
            return true;
        }

        if(number1 == 0 && number2 == 8 && number3 == 9){
            return true;
        }

        if(number1 == 0 && number2 == 1 && number3 == 9){
            return true;
        }

        //情况2：对子也是回
        if(number1 == number2 || number2 == number3 || number1 == number3){
            return true;
        }

        //情况3：3数之和为13也是回
        if(number1 + number2 + number3 == 13){
            return true;
        }

        //情况4：3数之和为14也是回
        if(number1 + number2 + number3 == 14){
            return true;
        }

        return false;
    }














    @Override
    public GamesBidHistory selectGamesBidHistoryById(Long id) {
        GamesBidHistory landInfoVos = this.baseMapper.selectGamesBidHistoryById(id);
        return landInfoVos;
    }

    @Override
    public GamesBidHistory selectGamesBidHistoryByBidNo(String bidNo) {
        return baseMapper.selectGamesBidHistoryByBidNo(bidNo);
    }

    @Override
    public List<GamesBidHistory> selectGamesBidHistoryList(GamesBidHistory dto) {
        List<GamesBidHistory> landInfoVos = this.baseMapper.selectGamesBidHistoryList(dto);
        return landInfoVos;
    }

    @Override
    public GamesBidHistory selectGamesBidHistoryByLast() {
        return this.baseMapper.selectGamesBidHistoryByLast();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertGamesBidHisotry(GamesBidHistory dto) {
        boolean save =false;
        GamesBidHistory landInfo = new GamesBidHistory();
        BeanUtils.copyProperties(dto,landInfo);
        save = this.save(landInfo);
        return save;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateGamesBidHistory(GamesBidHistory dto) {
        boolean save =false;
        GamesBidHistory landInfo = new GamesBidHistory();
        BeanUtils.copyProperties(dto,landInfo);
        //修改百事通信息
        save = this.updateById(landInfo);
        return save;
    }

    @Override
    public Boolean deleteGamesBidHistoryByIds(List<Long> ids) {
        return this.removeByIds(ids);
    }
}
